namespace SimpleWebServices.Configuration
{
    using System;
    using System.Configuration;
    using System.Linq;
    using System.Xml;
    using SimpleWebServices.Data;

    public sealed class RepositoryConfiguration : IConfigurationSectionHandler
    {
        public static void Clear()
        {
            RepositoryConfiguration.Settings().Clear();
        }

        public static void Reset()
        {
            ConfigurationManager.RefreshSection("simplewebservices/repositories");
        }

        public static IRepository Resolve<T>()
            where T : IRecord
        {
            return RepositoryConfiguration.Settings()[typeof(T).Name];
        }

        public static AbsoluteUri ToUrn<T>(string path)
            where T : IRecord
        {
            return RepositoryConfiguration.ToUrn(RepositoryConfiguration.Setting<T>(), path);
        }

        public static RepositorySettingCollection Settings()
        {
            return RepositoryConfiguration.Settings("simplewebservices/repositories");
        }

        public static RepositorySettingCollection Settings(string sectionName)
        {
            RepositorySettingCollection result = ConfigurationManager.GetSection(sectionName) as RepositorySettingCollection;

            return result ?? new RepositorySettingCollection();
        }

        public object Create(object parent, object configContext, XmlNode section)
        {
            RepositorySettingCollection result = null;

            if (section != null)
            {
                try
                {
                    result = section.OuterXml.Deserialize<RepositorySettingCollection>();
                }
                catch (Exception exception)
                {
                    throw new ConfigurationErrorsException(exception.Message, exception, section);
                }
            }

            return result ?? new RepositorySettingCollection();
        }

        private static RepositorySetting Setting<T>()
            where T : IRecord
        {
            return RepositoryConfiguration.Settings().Where(x => string.Equals(x.Key, typeof(T).Name, StringComparison.Ordinal)).FirstOrDefault();
        }

        private static AbsoluteUri ToUrn(RepositorySetting setting, string path)
        {
            string urn = RepositoryConfiguration.Settings().Urn;

            if (null != setting && null != setting.Urn)
            {
                urn = setting.Urn;
            }

            return RepositoryConfiguration.ToUrn(urn, path);
        }

        private static AbsoluteUri ToUrn(string urn, string path)
        {
            if (null == urn)
            {
                throw new ArgumentNullException("urn");
            }
            else if (0 == urn.Length)
            {
                throw new ArgumentOutOfRangeException("urn");
            }

            if (urn.EndsWith("/", StringComparison.Ordinal))
            {
                urn = urn.Substring(0, urn.Length - 1);
            }

            path = path ?? string.Empty;

            if (path.StartsWith("/", StringComparison.Ordinal))
            {
                path = path.Substring(1);
            }

            return string.Concat(urn, "/", (RelativeUri)path);
        }
    }
}